home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / Timing / EngClock96.lha / EngClock96 / Source / play8svx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-01  |  24.0 KB  |  869 lines

  1.  
  2. /** Play8SVX.c ************************************************************** 
  3.  * 
  4.  * Read and play sound sample from an IFF file.  21Jan85 
  5.  * 
  6.  * By Steve Hayes, Electronic Arts. 
  7.  * This software is in the public domain. 
  8.  * 
  9.  * Modified 05/91 for use with iffparse & to play notes - CAS_CBM
  10.  * requires linkage with several IFF modules - see Makefile
  11.  * 37.10 - checks for compression type, fails if unknown
  12.  *         changed "clock" variable to "tclock" to not override
  13.  *           some built-in variable of Manx's called "clock"
  14.  ****************************************************************************/ 
  15.  
  16. #include <exec/types.h>
  17.  
  18. #include "iffp/8svxapp.h"
  19.  
  20. #include <exec/execbase.h>
  21. #include <graphics/gfxbase.h>
  22. #include <clib/alib_protos.h>
  23. #include <libraries/iffparse.h>
  24. //#include <proto/exec.h>
  25. //#include <proto/dos.h>
  26. //#include <proto/iffparse.h>
  27. //#include <proto/intuition.h>
  28. #include <stdio.h>
  29. #include <exec/memory.h>
  30. #include <devices/audio.h>
  31. #include <exec/devices.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <intuition/intuition.h>
  35. #include <pragmas/xpkmaster_pragmas.h>
  36. #include <libraries/xpk.h>
  37. #include <libraries/xpksub.h>
  38.  
  39. #include <clib/exec_protos.h>
  40. #include <clib/dos_protos.h>
  41. #include <clib/intuition_protos.h>
  42. #include <clib/iffparse_protos.h>
  43. #include <libraries/iffparse.h>
  44.  
  45. /* prototypes for our functions */
  46. void cleanup(void);
  47. void DUnpack(BYTE source[], LONG n, BYTE dest[]);
  48. BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x);
  49. LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename);
  50. void UnloadSample(struct EightSVXInfo *esvx);
  51. LONG LoadSBody(struct EightSVXInfo *esvx);
  52. void UnloadSBody(struct EightSVXInfo *esvx);
  53. BOOL playsam(char *esvxname);
  54. void msg(char *msg);
  55. char *checkxpk(char *name);
  56. void main(int argc, char *argv[]);
  57. ULONG filesize(char *file);
  58. extern int getoct(int max);
  59.  
  60. LONG OpenAudio(void);
  61. void CloseAudio(void);
  62. LONG PlaySample(struct EightSVXInfo *esvx,
  63.         LONG octave, LONG note, UWORD volume, ULONG delay);
  64.  
  65. struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio *aio1,
  66.         BYTE *samptr, LONG ssize, ULONG period, UWORD volume);
  67.  
  68.  
  69. #include "play8svx_rev.h"
  70.  
  71. /* 8SVX Property chunks to be grabbed
  72.  */
  73. LONG    esvxprops[] = {
  74.         ID_8SVX, ID_VHDR,
  75.         ID_8SVX, ID_NAME,
  76.         ID_8SVX, ID_ATAK,
  77.         ID_8SVX, ID_RLSE,
  78.         ID_8SVX, ID_AUTH,
  79.         ID_8SVX, ID_Copyright,
  80.         TAG_DONE
  81.         };
  82.  
  83. /* 8SVX Collection chunks (more than one in file) to be gathered */
  84. LONG    esvxcollects[] = {
  85.         ID_8SVX, ID_ANNO,
  86.         TAG_DONE
  87.         };
  88.  
  89. /* 8SVX Chunk to stop on */
  90. LONG    esvxstops[] = {
  91.         ID_8SVX, ID_BODY,
  92.         TAG_DONE
  93.         };
  94.  
  95.  
  96. UBYTE nomem[]  = "Not enough memory\n";
  97. UBYTE noiffh[] = "Can't alloc iff\n";
  98.  
  99.  
  100. struct Library *XpkBase;
  101.  
  102. /* For our allocated EightSVXInfo */
  103. struct EightSVXInfo  *esvx = NULL;
  104.  
  105. extern struct IntuiText ok_text;
  106. extern struct IntuitionBase *IntuitionBase;
  107. extern struct GfxBase *GfxBase;
  108. extern struct Library *UtilityBase;
  109. extern struct Library *GadToolsBase;
  110. extern struct Library *DiskfontBase;
  111. extern struct Library *AslBase;
  112. extern struct Library *IFFParseBase;
  113. extern struct Library *DOSBase;
  114.  
  115. struct IntuiText msg_text={
  116.       1,0,JAM1,16,9,NULL,NULL,NULL };
  117. /* 
  118.  * MAIN 
  119.  */
  120. BOOL playsam(char *esvxname)
  121.    {
  122.    LONG error=0L;
  123.  
  124.     if(!(IFFParseBase=OpenLibrary("iffparse.library",0))) 
  125.         return(0);
  126.     
  127. /* 
  128.  * Alloc one EightSVXInfo struct
  129.  */
  130.     if(!(esvx = (struct EightSVXInfo *)
  131.     AllocMem(sizeof(struct EightSVXInfo),MEMF_PUBLIC|MEMF_CLEAR))) {
  132.         msg("Unable to allocate memory!");
  133.         return(0);
  134.     }
  135. /*
  136.  * Here we set up our EightSVXInfo fields for our
  137.  * application.
  138.  * Above we have defined the propery and collection chunks
  139.  * we are interested in (some required like VHDR).
  140.  * We want to stop on BODY.
  141.  */
  142.     esvx->ParseInfo.propchks    = esvxprops;
  143.     esvx->ParseInfo.collectchks    = esvxcollects;
  144.     esvx->ParseInfo.stopchks    = esvxstops;
  145. /* 
  146.  * Alloc the IFF handle for the frame
  147.  */
  148.     if(!(esvx->ParseInfo.iff = AllocIFF())) {
  149.     msg("Error parsing IFF!");
  150.     return(0);
  151.     }
  152.  
  153.  
  154.     if(!(error = LoadSample(esvx, esvxname)))
  155.     {
  156.     if(!(error = OpenAudio()))
  157.         {
  158.         /* If we think this is a sound effect, play it as such (note=-1) */
  159.         if((esvx->Vhdr.ctOctave==1)&&(esvx->Vhdr.samplesPerSec)
  160.         &&(esvx->Vhdr.oneShotHiSamples)&&(!esvx->Vhdr.repeatHiSamples))
  161.         {
  162.         PlaySample(esvx,0,-1,64,0);
  163.         }
  164.         /* Else play it like an instrument */
  165.         else
  166.         {
  167.              PlaySample(esvx,0,getoct(11),64,50);
  168.         }
  169.         CloseAudio();
  170.         }
  171.         else msg("error opening audio device");
  172.     }
  173.     else
  174.         msg("Something went wrong (IFF)");
  175.  
  176.     cleanup();
  177.     return(1);
  178.     }
  179.  
  180.  
  181.  
  182. void cleanup()
  183.     {
  184.        
  185.    if(esvx)        
  186.     {
  187.     DD(bug("About to UnloadSample\n"));
  188.     UnloadSample(esvx);
  189.  
  190.     DD(bug("About to FreeIFF\n"));
  191.     if(esvx->ParseInfo.iff)     FreeIFF(esvx->ParseInfo.iff);
  192.  
  193.     DD(bug("About to free EightSVXInfo\n"));
  194.         FreeMem(esvx,sizeof(struct EightSVXInfo));
  195.     }
  196.  
  197.     
  198.     DeleteFile("ram:engclock.temp");
  199.     CloseLibrary(IFFParseBase);
  200.    }
  201.  
  202.  
  203. /* OpenAudio
  204.  *
  205.  * Opens audio device for one audio channel, 2 IO requests
  206.  * Returns 0 for success
  207.  *
  208.  * Based on code by Dan Baker
  209.  */
  210.  
  211. UBYTE           whichannel[] = { 1,2,4,8 };
  212.  
  213. /* periods for scale starting at   65.40Hz (C) with 128 samples per cycle
  214.  *                            or  130.81Hz (C) with  64 samples per cycle
  215.  *                            or  261.63Hz (C) with  32 samples per cycle
  216.  *                            or  523.25Hz (C) with  16 samples per cycle
  217.  *                            or 1046.50Hz (C) with   8 samples per cycle
  218.  *                            or 2093.00Hz (C) with   4 samples per cycle
  219.  */
  220.  
  221. UWORD   per_ntsc[12]= { 428, 404, 380, 360,
  222.             340, 320, 302, 286,
  223.             270, 254, 240, 226 };
  224.  
  225. /* periods adjusted for system clock frequency */
  226. UWORD   per[12];
  227.  
  228. /* Note - these values 3579545 NTSC, 3546895 PAL */
  229. #define NTSC_CLOCK 3579545L
  230. #define PAL_CLOCK  3546895L
  231.  
  232. #define AIOCNT 4
  233. struct     IOAudio *aio[AIOCNT] = {NULL};       /* Ptrs to IO blocks for commands  */
  234.  
  235. struct     MsgPort *port;       /* Pointer to a port so the device can reply */
  236. BOOL    devopened;
  237. ULONG    tclock = NTSC_CLOCK;    /* Will check for PAL and change if necessary */
  238.  
  239.  
  240. LONG OpenAudio()
  241. {
  242. extern    struct ExecBase *SysBase;
  243. LONG     error=0L;
  244. ULONG   period;
  245. int    k;
  246.  
  247. if(devopened)    return(-1);
  248.  
  249. /*-------------------------------------------------------------------------*/
  250. /* Ask the system if we are PAL or NTSC and set clock constant accordingly */
  251. /*-------------------------------------------------------------------------*/
  252.     if(((struct GfxBase *)GfxBase)->DisplayFlags & PAL)
  253.         tclock = PAL_CLOCK;
  254.     else
  255.         tclock = NTSC_CLOCK;
  256.     
  257.  
  258.  
  259. /* calculate period values for one octave based on system clock */
  260. for(k=0; k<12; k++)
  261.     {
  262.     period = ((per_ntsc[k] * tclock) + (NTSC_CLOCK >> 1)) / NTSC_CLOCK;
  263.     per[k] = period;
  264.     D(bug("per[%ld]=%ld ",k,per[k]));
  265.     }
  266. D(bug("\n"));
  267.  
  268. /*-------------------------------------------------------------------*/
  269. /* Create a reply port so the audio device can reply to our commands */
  270. /*-------------------------------------------------------------------*/
  271. if(!(port=CreatePort(0,0)))
  272.     { error = 1; goto bailout; }
  273.  
  274. /*--------------------------------------------------------------------------*/
  275. /*  Create audio I/O blocks so we can send commands to the audio device     */
  276. /*--------------------------------------------------------------------------*/
  277. for(k=0; k<AIOCNT; k++)
  278.     {
  279.     if(!(aio[k]=(struct IOAudio *)CreateExtIO(port,sizeof(struct IOAudio))))
  280.     { error = k+2; goto bailout; }
  281.     }
  282.  
  283. /*----------------------------------------------------------------------*/
  284. /* Set up the audio I/O block for channel allocation:                   */
  285. /* ioa_Request.io_Message.mn_ReplyPort is the address of a reply port.  */
  286. /* ioa_Request.io_Message.mn_Node.ln_Pri sets the precedence (priority) */
  287. /*   of our use of the audio device. Any tasks asking to use the audio  */
  288. /*   device that have a higher precedence will steal the channel from us.*/
  289. /* ioa_Request.io_Command is the command field for IO.                  */
  290. /* ioa_Request.io_Flags is used for the IO flags.                       */
  291. /* ioa_AllocKey will be filled in by the audio device if the allocation */
  292. /*   succeeds. We must use the key it gives for all other commands sent.*/
  293. /* ioa_Data is a pointer to the array listing the channels we want.     */
  294. /* ioa_Length tells how long our list of channels is.                   */
  295. /*----------------------------------------------------------------------*/
  296. aio[0]->ioa_Request.io_Command               = ADCMD_ALLOCATE;
  297. aio[0]->ioa_Request.io_Flags                 = ADIOF_NOWAIT;
  298. aio[0]->ioa_AllocKey                         = 0;
  299. aio[0]->ioa_Data                             = whichannel;
  300. aio[0]->ioa_Length                           = sizeof(whichannel);
  301.  
  302. /*-----------------------------------------------*/
  303. /* Open the audio device and allocate a channel  */
  304. /*-----------------------------------------------*/
  305. if(!(OpenDevice("audio.device",0L, (struct IORequest *) aio[0] ,0L)))
  306.     devopened = TRUE;
  307. else { error = 5; goto bailout; }
  308.  
  309. /* Clone the flags, channel allocation, etc. into other IOAudio requests */
  310. for(k=1; k<AIOCNT; k++)    *aio[k] = *aio[0];
  311.  
  312. bailout:
  313. if(error)    
  314.     {
  315.     msg("OpenAudio errored out");
  316.     CloseAudio();
  317.     }
  318. return(error);
  319. }
  320.  
  321.  
  322. /* CloseAudio
  323.  *
  324.  * Close audio device as opened by OpenAudio, null out pointers
  325.  */
  326. void CloseAudio()
  327. {
  328. int k;
  329.  
  330. D(bug("Closing audio device...\n"));
  331.  
  332. /* Note - we know we have no outstanding audio requests */
  333. if(devopened)
  334.     {
  335.     CloseDevice((struct IORequest *) aio[0]);
  336.     devopened = FALSE;
  337.     }
  338.  
  339. for(k=0; k<AIOCNT; k++)
  340.     {
  341.     if(aio[k])     DeleteExtIO((struct IORequest *)aio[k]), aio[k] = NULL;
  342.     }
  343.  
  344. if(port)       DeletePort(port),  port = NULL;
  345. }
  346.  
  347.  
  348. /** PlaySample() **********************************************
  349.  * 
  350.  * Play a note in octave for delay/50ths of a second 
  351.  * OR Play a sound effect (set octave and note to 0, -1)
  352.  *
  353.  * Requires successful OpenAudio() called previously
  354.  *
  355.  * When playing notes:
  356.  * Expects note values between 0 (C) and 11 (B#)
  357.  * Uses largest octave sample in 8SVX as octave 0, next smallest
  358.  *   as octave 1, etc.
  359.  *
  360.  * Notes - this simple example routine does not do ATAK and RLSE)
  361.  *       - use of Delay for timing is simplistic, synchronous, and does
  362.  *        not take into account that the oneshot itself may be
  363.  *        longer than the delay.
  364.  *         Use timer.device for more accurate asynchronous delays
  365.  *
  366.  *************************************************************************/
  367. /* Max playable sample in one IO request is 128K */
  368. #define MAXSAMPLE 131072
  369.  
  370. LONG    PlaySample(struct EightSVXInfo *esvx,
  371.             LONG octave, LONG note, UWORD volume, ULONG delay)
  372. {
  373. /* pointers to outstanding requests */
  374. struct        IOAudio    *aout0=NULL, *aout1=NULL;    
  375. ULONG        period;
  376. LONG        osize, rsize;
  377. BYTE        *oneshot, *repeat;
  378.  
  379. if(!devopened)    return(-1);
  380.  
  381. if(note > 11) note=0;
  382.  
  383. if( note == -1 ) period = tclock / esvx->Vhdr.samplesPerSec;
  384. else          period = per[note]; /* table set up by OpenAudio */
  385.  
  386. if(octave > esvx->Vhdr.ctOctave) octave = 0;
  387. if(volume > 64)    volume = 64;
  388.  
  389. oneshot = esvx->osamps[octave];
  390. osize   = esvx->osizes[octave];
  391. repeat  = esvx->rsamps[octave];
  392. rsize   = esvx->rsizes[octave];
  393.  
  394. D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
  395.     oneshot, osize, repeat, rsize));
  396.  
  397. /*------------------------------------------------------------*/
  398. /* Set up audio I/O blocks to play a sample using CMD_WRITE.  */
  399. /* Set up one request for the oneshot and one for repeat      */
  400. /* (all ready for simple case, but we may not need both)      */
  401. /* The io_Flags are set to ADIOF_PERVOL so we can set the     */
  402. /*    period (speed) and volume with the our sample;          */
  403. /* ioa_Data points to the sample; ioa_Length gives the length */
  404. /* ioa_Cycles tells how many times to repeat the sample       */
  405. /* If you want to play the sample at a given sampling rate,   */
  406. /* set ioa_Period = clock/(given sampling rate)               */
  407. /*------------------------------------------------------------*/
  408. aio[0]->ioa_Request.io_Command             =CMD_WRITE;
  409. aio[0]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  410. aio[0]->ioa_Data                           =oneshot;
  411. aio[0]->ioa_Length                         =osize;
  412. aio[0]->ioa_Period                         =period;
  413. aio[0]->ioa_Volume                         =volume;
  414. aio[0]->ioa_Cycles                         =1;
  415.  
  416. aio[2]->ioa_Request.io_Command             =CMD_WRITE;
  417. aio[2]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  418. aio[2]->ioa_Data                           =repeat;
  419. aio[2]->ioa_Length                         =rsize;
  420. aio[2]->ioa_Period                         =period;
  421. aio[2]->ioa_Volume                         =volume;
  422. aio[2]->ioa_Cycles                         =0;    /* repeat until stopped */
  423.  
  424. /*---------------------------------------------------*/
  425. /* Send the command to start a sound using BeginIO() */
  426. /* Go to sleep and wait for the sound to finish with */
  427. /* WaitIO() to wait and get the get the ReplyMsg     */
  428. /*---------------------------------------------------*/
  429.  
  430. if(osize)
  431.     {
  432.     /* Simple case for oneshot sample <= 128K (ie. most samples) */
  433.     if(osize <= MAXSAMPLE)    BeginIO((struct IORequest *)(aout0=aio[0]));
  434.  
  435.     /* Note - this else case code is for samples >128K */
  436.     else
  437.     {
  438.     *aio[1] = *aio[0];
  439.     aout0 = playbigsample(aio[0],aio[1],oneshot,osize,period,volume);
  440.     }
  441.      }
  442.  
  443. if(rsize)
  444.     {
  445.     /* Simple case for repeat sample <= 128K (ie. most samples) */
  446.     if(rsize <= MAXSAMPLE)    BeginIO((struct IORequest *)(aout1=aio[2]));
  447.  
  448.     /* Note - this else case code is for samples >128K */
  449.     else
  450.     {
  451.     *aio[3] = *aio[2];
  452.     aout1 = playbigsample(aio[2],aio[3],repeat,rsize,period,volume);
  453.     }
  454.      }
  455.  
  456. if(delay)    Delay(delay);    /* crude timing for notes */
  457.  
  458. /* Wait for any requests we still have out */
  459. if(aout0) WaitIO((struct IORequest *)aout0);
  460.  
  461. if(aout1)
  462.    {
  463.    if(note >= 0) AbortIO((struct IORequest *)aout1);    /* if a note, stop it now */
  464.    WaitIO((struct IORequest *)aout1);
  465.    }
  466.  
  467. }
  468.  
  469.  
  470. /** playbigsample() ********************************************************
  471.  * 
  472.  *  called by playsample to deal with samples > 128K
  473.  *
  474.  *  wants pointers to two ready-to-use IOAudio iorequest blocks
  475.  *
  476.  *  returns pointer to the IOAudio request that is still out
  477.  *   or NULL if none (error)
  478.  *************************************************************************/
  479.  
  480. struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio* aio1,
  481.             BYTE *samptr, LONG ssize, ULONG period, UWORD volume)
  482. {
  483. struct IOAudio *aio[2];
  484. LONG   size;
  485. int    req=0, reqn=1;    /* current and next IOAudio request indexes */
  486.  
  487. if((!aio0)||(!aio1)||(ssize < MAXSAMPLE))    return(NULL);
  488.  
  489. aio[req]  = aio0;
  490. aio[reqn] = aio1;
  491.  
  492. /* start the first 128 K playing */
  493. aio[req]->ioa_Request.io_Command             =CMD_WRITE;
  494. aio[req]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  495. aio[req]->ioa_Data                           =samptr;
  496. aio[req]->ioa_Length                 =MAXSAMPLE;
  497. aio[req]->ioa_Period                         =period;
  498. aio[req]->ioa_Volume                         =volume;
  499. aio[req]->ioa_Cycles                         =1;
  500. BeginIO((struct IORequest*)aio[req]);
  501.  
  502. for(samptr=samptr + MAXSAMPLE, size = ssize - MAXSAMPLE;
  503.     size > 0;
  504.         samptr += MAXSAMPLE)
  505.     {
  506.     /* queue the next piece of sample */
  507.     reqn = req ^ 1;    /* alternate IO blocks 0 and 1 */
  508.     aio[reqn]->ioa_Request.io_Command             =CMD_WRITE;
  509.     aio[reqn]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  510.     aio[reqn]->ioa_Data                           =samptr;
  511.     aio[reqn]->ioa_Length = (size > MAXSAMPLE) ? MAXSAMPLE : size;
  512.     aio[reqn]->ioa_Period                         =period;
  513.     aio[reqn]->ioa_Volume                         =volume;
  514.     aio[reqn]->ioa_Cycles                         =1;
  515.     BeginIO((struct IORequest*)aio[reqn]);
  516.  
  517.     /* Wait for previous request to finish */
  518.     WaitIO((struct IORequest *)aio[req]);
  519.     /* decrement size */
  520.     size = (size > MAXSAMPLE) ? size-MAXSAMPLE : 0;
  521.     req = reqn;        /* switch between aio[0] and aio[1] */
  522.     }
  523. return(aio[reqn]);
  524. }
  525.  
  526. /** LoadSample() **********************************************************
  527.  * 
  528.  * Read 8SVX, given an initialized EightSVXInfo with not-in-use IFFHandle,
  529.  *   and filename.  Leaves the IFFHandle open so you can FindProp()
  530.  *   additional chunks or copychunks().  You must UnloadSample()
  531.  *   when done.  UnloadSample will closeifile if the file is still
  532.  *   open.
  533.  *
  534.  * Fills in esvx->Vhdr and Name, and allocates/loads esvx->sample,
  535.  *   setting esvx->samplebytes to size for deallocation.
  536.  *
  537.  * Returns 0 for success of an IFFERR (libraries/iffparse.h)
  538.  *************************************************************************/
  539. LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename)
  540.     {
  541.     struct IFFHandle *iff;
  542.     struct StoredProperty *sp;
  543.     Voice8Header *vhdr;
  544.     BYTE *oneshot, *repeat;
  545.     ULONG osize, rsize, spcyc;
  546.     int oct;
  547.     LONG error = 0L;
  548.  
  549.     D(bug("LoadSample:\n"));
  550.     
  551.     if(!esvx)                return(CLIENT_ERROR);
  552.     if(!(iff=esvx->ParseInfo.iff))    return(CLIENT_ERROR);
  553.  
  554.     filename=(UBYTE *)checkxpk(filename);
  555.  
  556.     if(!(error = openifile((struct ParseInfo *)esvx, filename, IFFF_READ)))
  557.     {
  558.     error = parseifile((struct ParseInfo *)esvx,
  559.             ID_FORM, ID_8SVX,
  560.             esvx->ParseInfo.propchks,
  561.             esvx->ParseInfo.collectchks,
  562.             esvx->ParseInfo.stopchks);
  563.  
  564.     D(bug("LoadSample: after parseifile - error = %ld\n",error));
  565.  
  566.     if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
  567.         {
  568.         if(contextis(iff,ID_8SVX,ID_FORM))
  569.         {
  570.         D(bug("LoadSample: context is 8SVX\n"));
  571.         if(!(sp = FindProp(iff,ID_8SVX,ID_VHDR)))
  572.             {
  573.             message("No 8SVX.VHDR!");
  574.             error = IFFERR_SYNTAX;
  575.             }
  576.         else
  577.             {
  578.             D(bug("LoadSample: Have VHDR\n"));
  579.             /* copy Voice8Header into frame */
  580.             vhdr = (Voice8Header *)(sp->sp_Data);
  581.             *(&esvx->Vhdr) = *vhdr;
  582.             /* copy name if any */
  583.             esvx->name[0]='\0';
  584.             if(sp = FindProp(iff,ID_8SVX,ID_NAME))
  585.             {
  586.             strncpy(esvx->name,sp->sp_Data,sp->sp_Size);
  587.             esvx->name[MIN(sp->sp_Size,79)] = '\0';
  588.             }
  589.                 error = LoadSBody(esvx);
  590.             D(bug("LoadSample: After LoadSBody - error = %ld\n",error));
  591.             if(!error)
  592.             {
  593.             osize   = esvx->Vhdr.oneShotHiSamples;
  594.             rsize   = esvx->Vhdr.repeatHiSamples;
  595.             spcyc    = esvx->Vhdr.samplesPerHiCycle;
  596.             if(!spcyc) spcyc = esvx->Vhdr.repeatHiSamples;
  597.             if(!spcyc) spcyc = 8;
  598.  
  599.             oneshot = esvx->sample;
  600.  
  601.             for(oct = esvx->Vhdr.ctOctave-1; oct >= 0;
  602.                  oct--, oneshot+=(osize+rsize),
  603.                     osize <<= 1, rsize <<=1, spcyc <<=1)
  604.                     {
  605.                     repeat  = oneshot + osize;
  606.                 esvx->osizes[oct] = osize;
  607.                 if(osize) esvx->osamps[oct] = oneshot;
  608.                 else      esvx->osamps[oct] = 0;
  609.                 esvx->rsizes[oct] = rsize;
  610.                 if(rsize) esvx->rsamps[oct] = repeat;
  611.                 else      esvx->rsamps[oct] = 0;
  612.                 esvx->spcycs[oct] = spcyc;
  613.  
  614.              D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
  615.                 oneshot, osize, repeat, rsize));
  616.  
  617.                 }
  618.                 }
  619.             }
  620.         }
  621.         else
  622.         {
  623.         message("Not an 8SVX\n");
  624.         error = NOFILE;
  625.         }
  626.         }
  627.     }
  628.  
  629.     if(error)
  630.     {
  631.     closeifile((struct ParseInfo *)esvx);
  632.     UnloadSample(esvx);
  633.     }
  634.     return(error);
  635.     }
  636.  
  637.  
  638. /** UnloadSample() *******************************************************
  639.  * 
  640.  * Frees and closes everything opened/alloc'd by LoadSample()
  641.  *
  642.  *************************************************************************/
  643. void UnloadSample(struct EightSVXInfo *esvx)
  644.     {
  645.     if(esvx)
  646.     {
  647.     UnloadSBody(esvx);
  648.     closeifile((struct ParseInfo *)esvx);
  649.     }
  650.     }
  651.  
  652.  
  653. /** LoadSBody() ***********************************************************
  654.  * 
  655.  * Read a 8SVX Sample BODY into RAM.  
  656.  * 
  657.  *************************************************************************/
  658. LONG LoadSBody(struct EightSVXInfo *esvx)
  659.     {
  660.     struct IFFHandle *iff;
  661.     LONG sbytes, rlen, error = 0L; 
  662.     ULONG memtype;
  663.     Voice8Header *vhdr = &esvx->Vhdr;
  664.     BYTE *t;
  665.  
  666.     D(bug("LoadSBody:\n"));
  667.  
  668.     if(!(iff=esvx->ParseInfo.iff))    return(CLIENT_ERROR);
  669.     if(!esvx)                return(CLIENT_ERROR);
  670.  
  671.     if(!(currentchunkis(iff,ID_8SVX,ID_BODY)))
  672.     {
  673.     message("LoadSBody: not at BODY!");
  674.     return(IFFERR_READ);
  675.     }
  676.  
  677.     sbytes  = ChunkMoreBytes(CurrentChunk(iff)); 
  678.  
  679.     /* if we have to decompress, let's just load it into public mem */
  680.     memtype = vhdr->sCompression ? MEMF_PUBLIC : MEMF_CHIP;
  681.  
  682.     D(bug("LoadSBody: samplebytes=%ld, compression=%ld\n",
  683.             sbytes,vhdr->sCompression));
  684.     
  685.     if(!(esvx->sample = (BYTE *)AllocMem(sbytes, memtype))) 
  686.     {
  687.         error = IFFERR_NOMEM;    /* used to be flagged as client error */ 
  688.     }
  689.     else 
  690.     {
  691.     D(bug("LoadSBody: have load buffer\n"));
  692.     esvx->samplebytes = sbytes; 
  693.         if(rlen=ReadChunkBytes(iff,esvx->sample,sbytes) != sbytes)
  694.         error = IFFERR_READ;
  695.  
  696.     if(error)
  697.         {
  698.         D(bug("LoadSBody: ReadChunkBytes error = %ld, read %ld bytes\n",
  699.             error));
  700.         }
  701.     else if (vhdr->sCompression == sCmpFibDelta ) /* Decompress, if needed. */
  702.         {
  703.             if(t = (BYTE *)AllocMem(sbytes<<1, MEMF_CHIP)) 
  704.         {
  705.         D(bug("LoadSBody: have decompression buffer\n"));
  706.                 DUnpack(esvx->sample, sbytes, t); 
  707.                 FreeMem(esvx->sample, sbytes); 
  708.                 esvx->sample = t;
  709.                 esvx->samplebytes = sbytes << 1;
  710.         }
  711.         else
  712.         {
  713.         error = IFFERR_NOMEM;
  714.         }
  715.         } 
  716.     else if (vhdr->sCompression)    /* unknown ompression method */
  717.         {
  718.         error = CLIENT_ERROR;
  719.         }
  720.     }
  721.     if(error)    UnloadSample(esvx);
  722.     return(error);
  723.     } 
  724.  
  725.  
  726. /** UnloadSBody() ********************************************************
  727.  * 
  728.  * Deallocates esvx->smaple  
  729.  * 
  730.  *************************************************************************/
  731. void UnloadSBody(struct EightSVXInfo *esvx)
  732.     {
  733.     if(esvx)
  734.     {
  735.     if(esvx->sample)
  736.         {
  737.         DD(bug("About to free SBody\n"));
  738.         FreeMem(esvx->sample,esvx->samplebytes);
  739.         esvx->sample = NULL;
  740.         }
  741.     esvx->samplebytes = NULL;
  742.     }
  743.     }
  744.  
  745.  
  746. /* DUnpack.c --- Fibonacci Delta decompression by Steve Hayes */
  747.  
  748. /* Fibonacci delta encoding for sound data */
  749. BYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
  750.  
  751. /* Unpack Fibonacci-delta encoded data from n byte source
  752.  * buffer into 2*n byte dest buffer, given initial data
  753.  * value x.  It returns the lats data value x so you can
  754.  * call it several times to incrementally decompress the data.
  755.  */
  756.  
  757. BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x)
  758.    {
  759.    BYTE d;
  760.    LONG i, lim;
  761.  
  762.    lim = n << 1;
  763.    for (i=0; i < lim; ++i)
  764.       {
  765.       /* Decode a data nibble, high nibble then low nibble */
  766.       d = source[i >> 1];    /* get a pair of nibbles */
  767.       if (i & 1)             /* select low or high nibble */
  768.          d &= 0xf;           /* mask to get the low nibble */
  769.       else
  770.          d >>= 4;            /* shift to get the high nibble */
  771.       x += codeToDelta[d];   /* add in the decoded delta */
  772.       dest[i] = x;           /* store a 1 byte sample */
  773.       }
  774.    return(x);
  775.    }
  776.  
  777. /* Unpack Fibonacci-delta encoded data from n byte
  778.  * source buffer into 2*(n-2) byte dest buffer.
  779.  * Source buffer has a pad byte, an 8-bit initial
  780.  * value, followed by n-2 bytes comprising 2*(n-2)
  781.  * 4-bit encoded samples.
  782.  */
  783.  
  784. void DUnpack(source, n, dest)
  785. BYTE source[], dest[];
  786. LONG n;
  787.    {
  788.    D1Unpack(source+2, n-2, dest, source[1]);
  789.    }
  790.  
  791.  
  792.  
  793. void msg(char *msg) {
  794.     msg_text.IText=msg;
  795.     ok_text.IText="Continue";
  796.     AutoRequest(NULL, &msg_text, NULL, &ok_text, (ULONG)NULL, (ULONG)NULL, 320, 100 );
  797. }
  798.  
  799. /* Testing purposes only! */
  800.  
  801. char *checkxpk(char *name) {
  802.     struct XpkFib xfib;
  803.     BPTR file;
  804.     struct TagItem tags1[]={
  805.         XPK_InName,NULL,
  806.         TAG_DONE
  807.     };
  808.     struct TagItem tags2[]={
  809.         XPK_InName,NULL,
  810.         XPK_OutName,NULL,
  811.         TAG_DONE
  812.     };
  813.     
  814.     tags1[0].ti_Data=(ULONG)name;
  815.                 
  816.     if(!(XpkBase=OpenLibrary("xpkmaster.library",0))) {
  817.         /* Cannot open xpk! */
  818.         return(name);
  819.     }
  820.  
  821.     /* Is it packed ? */
  822.     XpkExamine(&xfib,tags1);
  823.  
  824.     if(xfib.Type!=XPKTYPE_PACKED) {
  825.         /* Not packed */
  826.         CloseLibrary(XpkBase);
  827.         return(name);
  828.     } else {
  829.         /* Packed so unpack it first */
  830.         /* set up tags */
  831.         tags2[0].ti_Data=(ULONG)name;
  832.         tags2[1].ti_Data=(ULONG)"ram:engclock.temp";    
  833.  
  834.         XpkUnpack(tags2);
  835.         /* Check if we wrote anything... */
  836.         file=Open("ram:engclock.temp",MODE_OLDFILE);
  837.         if(file) {
  838.             if(FGetC(file)==EOF) {
  839.                 msg("Error unpacking file! 1");
  840.                 CloseLibrary(XpkBase);
  841.                 Close(file);
  842.                 return(0L);
  843.             }
  844.         } else {
  845.             msg("Error unpacking file! 2");
  846.             CloseLibrary(XpkBase);
  847.             return(0L);
  848.         }
  849.         CloseLibrary(XpkBase);
  850.         Close(file);
  851.         return("ram:engclock.temp");
  852.  
  853.     }
  854. }
  855.  
  856.  
  857. ULONG filesize(char *file) {
  858.     BPTR fp;
  859.     ULONG len;
  860.  
  861.     fp=Open(file,MODE_OLDFILE);
  862.     len=Seek(fp,0,OFFSET_END);
  863.     len=Seek(fp,0,OFFSET_BEGINNING);
  864.  
  865.     Close(fp);
  866.     return(len);
  867. }
  868.     
  869.